package com.specter.serv.service.impl;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import com.specter.mvc.view.json.JSON;
import com.specter.mvc.view.json.JSONObject;
import com.specter.mvc.web.WebContext;
import com.specter.serv.service.BidpService;
import com.specter.sure.core.StokenizorProvider;
import com.specter.utils.StringUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * 字典操作公共接口
 *
 * @author Liang.Wang
 * @since 2017-03-29
 */
@Slf4j
@Service
public class BidpServiceImpl implements BidpService {
	@Value("${thisapp.xdata.bidp.api.op:NONE}")
	private String op;
	@Value("${thisapp.xdata.bidp.api.ak:NONE}")
	private String ak;
	@Value("${thisapp.xdata.bidp.api.sk:NONE}")
	private String sk;
	private RestTemplate rest = new RestTemplate();
	private @Autowired StokenizorProvider storage;

	@Override
	public String token() {
		String key = "bidp:acis:token:string";
		String token = storage.get(key, String.class);
		if (token == null || storage.tokenValidate(token) == null) {
			String uri = op + "/sure/oauth/access_token";
			MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
			long ts = (new Date()).getTime();
			params.add("client_id", ak);
			params.add("timestamp", ts);
			params.add("signature",
					DigestUtils.md5DigestAsHex((String.format("AK:%s/TS:%s/SK:%s", ak, ts, sk)).getBytes()));
			token = rest.postForObject(uri, params, JSONObject.class).getObject("data").get("access_token");
			storage.set(key, token, 3600L);// 缓存7秒
			log.debug("Set token to storage success!");
		} else {
			log.debug("Get token from storage success!");
		}
		return token;
	}

	@Override
	public Object gws(String path) throws Exception {
		String cttype = WebContext.getRequest().getContentType();
        Map<String, Object> params = new HashMap<>();

        // application/x-www-form-urlencoded
        if (StringUtils.isBlank(cttype) || cttype.contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
            WebContext.getRequest().getParameterMap().forEach((k, v) -> params.put(k, v.length == 1 ? v[0] : v));
        }
        // application/json
        else if (cttype.contains(MediaType.APPLICATION_JSON_VALUE)) {
            return JSON.parseTo(IOUtils.toString(WebContext.getRequest().getInputStream(), StandardCharsets.UTF_8));
        }
        // multipart/form-data
        else if(cttype.contains(MediaType.MULTIPART_FORM_DATA_VALUE)) {
            // String v = new String(part.getInputStream().readAllBytes(), "UTF-8"); //文本
            WebContext.getRequest().getParts().forEach(e -> params.put(e.getName(), e));
        }
		
        return proxy(path, params);
	}

	@Override
	public String upd(MultipartFile file) {
		String uri = op + "/open/api/comp/tool/oss";
		MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
		params.add("path", "disable-mis-acis");
		try {
			params.add("file", new ByteArrayResource(file.getBytes()) {
				@Override
				public String getFilename() {
					return file.getOriginalFilename();
				}

				@Override
				public long contentLength() {
					return file.getSize();
				}
			});
		} catch (Exception e) {
			e.printStackTrace();
		}
		HttpHeaders headers = new HttpHeaders();
		headers.setBearerAuth(this.token());
		headers.setContentType(MediaType.MULTIPART_FORM_DATA);
		HttpEntity<?> request = new HttpEntity<>(params, headers);
		JSONObject json = rest.postForObject(uri, request, JSONObject.class);
		log.debug("upload response: {}", json.toString());
		return json.get("data");
	}

	@Override
	public JSONObject irs(String path, String citizenId) {
		JSONObject res = proxy(path, JSONObject.create().put("citizenId", citizenId));
		return res.get("data");
	}

	@Override
	public Boolean sms(String mobiles, String message) {
		proxy("/comp/tool/sms", (new JSONObject()).put("mobile", mobiles).put("content", message));
		return true;
	}

	/**
	 * 代理方法接口实现，采用spring代理接口，方法和类型和原方法保持一致
	 * 
	 * @param source 代码
	 * @param params 参数
	 * 
	 * @return 执行结果
	 */
	public <T, M> T proxy(String path, M para) {
		HttpHeaders headers = new HttpHeaders();
		headers.set(HttpHeaders.CONTENT_TYPE, Optional.ofNullable(WebContext.getRequest().getContentType()).orElse(MediaType.APPLICATION_FORM_URLENCODED_VALUE));
		headers.setBearerAuth(this.token());
		HttpMethod method = Optional.ofNullable(HttpMethod.valueOf(WebContext.getRequest().getMethod())).orElse(HttpMethod.GET);

		log.debug("代理数据接口：{}", path);
		Object body = para;
		if (headers.getContentType().toString().contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
			MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
			JSON.toJSONObject(para).toJavaObject().forEach(map::add);
			body = map;
		}
		T data = null;
		try {
			RequestEntity<?> req = new RequestEntity<>(body, headers, method, new URI("/open/api" + path));
			ResponseEntity<String> res = new RestTemplate().exchange(req, String.class);
			data = JSON.parse(res.getBody());
			log.debug("代理接口结果：{}", Objects.toString(data, "null"));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return data;
	}

}
